"""参数分析Pass - 重构版本

利用builtin_table的方法信息，简化参数使用分析，减少硬编码。
"""

from typing import Dict, Set, Any, Optional
from ..ir import (
    IRNode,
    IRFunctionNode,
    IRStmtBlock,
    IRAssign,
    IRAugAssign,
    IRExprStmt,
    IRReturn,
    IRForEach,
    IRForRange,
    IRIf,
    IRWhile,
    IRCall,
    IRAttribute,
    IRName,
)
from .base import BasePass, PassStage
from mcpy.symbol_meta import SymbolKind


class ParameterUsageInfo:
    """参数使用信息 - 简化版本"""

    def __init__(self, param_name: str):
        self.param_name = param_name
        self.is_read = False
        self.is_modified = False
        self.is_mutated = False
        self.read_count = 0
        self.modification_count = 0

    def get_cpp_parameter_type(
        self, base_cpp_type: str, param_node=None, ir_module=None
    ) -> str:
        """根据使用模式和配置确定C++参数类型

        优先级：
        1. 使用模式（修改检测）- 最高优先级，确保正确性
        2. 配置系统 (pass_by) - 次优先级，精确配置
        3. 启发式规则 - 兜底，处理未配置的情况

        Args:
            base_cpp_type: 基础 C++ 类型
            param_node: 参数节点（用于查找配置）
            ir_module: IR 模块（用于符号查找）
        """
        # 1. 如果参数被修改，必须使用非const引用（最高优先级，确保正确性）
        if self.is_modified or self.is_mutated:
            return f"{base_cpp_type}&"

        # 2. 尝试从配置系统获取 pass_by 策略（次优先级，精确配置）
        if param_node and ir_module:
            pass_by_strategy = self._get_pass_by_from_config(param_node, ir_module)
            if pass_by_strategy:
                return self._apply_pass_by_strategy(base_cpp_type, pass_by_strategy)

        # 3. 启发式规则（兜底，处理未配置的情况）
        # 注意：启发式规则应该保守，避免产生歧义

        # 检查是否是明确的简单类型
        if self._is_definitely_simple_type(base_cpp_type):
            return base_cpp_type

        # 检查是否是明确的复杂类型（包含命名空间或模板）
        if self._is_definitely_complex_type(base_cpp_type):
            return f"const {base_cpp_type}&"

        # 对于不确定的类型（如单字母类型名 T, U 等），默认使用 const 引用（安全）
        # 原因：
        # 1. 单字母类型通常是模板参数，可能是大对象
        # 2. 即使是简单类型，const T& 也只是多一次间接访问，不会导致错误
        # 3. 这比错误地按值传递大对象要安全得多
        return f"const {base_cpp_type}&"

    def _get_pass_by_from_config(self, param_node, ir_module):
        """从配置系统获取 pass_by 策略

        查找顺序：
        1. TypeInfo.pass_by（类型级别配置）
        2. 类型符号的 type_config.pass_by
        3. TypeVar 符号的 template_params.pass_by

        Returns:
            pass_by 策略字符串，如果没有找到则返回 None
        """
        # 获取参数的类型信息
        type_info = param_node.get_extension_param("inferred_type")
        if not type_info:
            return None

        # 1. TypeInfo 级别的 pass_by
        if hasattr(type_info, "pass_by") and type_info.pass_by:
            return type_info.pass_by

        # 2. TypeVar 符号的配置
        try:
            typevar_symbol = param_node.lookup_symbol(
                type_info.name,
                symbol_kinds=[SymbolKind.TYPE_PARAM],
            )
            if (
                typevar_symbol
                and typevar_symbol.template_params
                and len(typevar_symbol.template_params) > 0
            ):
                template_param = typevar_symbol.template_params[0]
                if template_param.pass_by != "auto":
                    return template_param.pass_by
        except:
            pass  # 查找失败，返回 None

        return None

    def _apply_pass_by_strategy(self, cpp_type: str, strategy: str) -> str:
        """应用传递策略"""
        if strategy == "value":
            return cpp_type
        elif strategy == "const_ref":
            return f"const {cpp_type}&"
        elif strategy == "rvalue_ref":
            return f"{cpp_type}&&"
        elif strategy == "auto":
            # auto 策略：根据类型复杂度决定
            if self._is_definitely_complex_type(cpp_type):
                return f"const {cpp_type}&"
            else:
                return cpp_type
        else:
            return cpp_type

    def _is_definitely_complex_type(self, cpp_type: str) -> bool:
        """判断是否是明确的复杂类型（高置信度）

        只有当确定是复杂类型时才返回 True，避免误判。
        包含以下特征：
        - 包含命名空间（::）
        - 包含模板参数（<>）
        - 已知的复杂类型名
        """
        clean_type = cpp_type.strip()
        # 移除修饰符
        for modifier in ["const ", "volatile ", "constexpr "]:
            if clean_type.startswith(modifier):
                clean_type = clean_type[len(modifier) :].strip()

        # 移除引用和指针
        clean_type = clean_type.rstrip("&*").strip()

        # 包含命名空间 -> 明确的复杂类型
        if "::" in clean_type:
            return True

        # 包含模板参数 -> 明确的复杂类型
        if "<" in clean_type and ">" in clean_type:
            return True

        return False

    def _is_definitely_simple_type(self, cpp_type: str) -> bool:
        """判断是否是明确的简单类型（高置信度）

        只有当确定是简单类型时才返回 True，避免误判。
        """
        clean_type = cpp_type.strip()
        # 移除修饰符
        for modifier in ["const ", "volatile ", "constexpr "]:
            if clean_type.startswith(modifier):
                clean_type = clean_type[len(modifier) :].strip()

        # 指针类型视为简单类型
        if clean_type.endswith("*"):
            return True

        # 移除引用
        if clean_type.endswith("&"):
            clean_type = clean_type[:-1].strip()

        # 已知的简单类型白名单
        simple_types = {
            "bool",
            "char",
            "int",
            "float",
            "double",
            "long",
            "short",
            "signed",
            "unsigned",
            "int8_t",
            "uint8_t",
            "int16_t",
            "uint16_t",
            "int32_t",
            "uint32_t",
            "int64_t",
            "uint64_t",
            "size_t",
            "ptrdiff_t",
            "ssize_t",
        }

        return clean_type in simple_types


class ParameterAnalysisPass(BasePass):
    """参数分析Pass - 重构版本

    职责：
    1. 分析函数参数的使用模式
    2. 利用builtin_table的方法信息判断修改性
    3. 为参数确定最优的C++类型
    """

    name = "parameter_analysis_v2"
    stage = PassStage.POST_ANALYSIS

    def __init__(self, config: Optional[Dict[str, Any]] = None):
        super().__init__()
        self.config = config or {}
        self.current_function_params: Set[str] = set()
        self.parameter_usage: Dict[str, ParameterUsageInfo] = {}
        self.current_module = None  # 保存当前模块引用

    def run(self, ir_module, context) -> Any:
        """运行参数分析Pass"""
        self.current_module = ir_module  # 保存模块引用
        self.visit_module(ir_module)
        return ir_module

    def visit_module(self, module):
        """访问模块中的所有节点"""
        for node in module.get_child_nodes():
            self.visit_node(node)

    def visit_node(self, node: IRNode):
        """访问IR节点"""
        if isinstance(node, IRFunctionNode):
            self.visit_function(node)
        else:
            # 递归访问子节点
            for child in node.get_child_nodes():
                self.visit_node(child)

    def visit_function(self, func_node: IRFunctionNode):
        """分析函数节点"""
        # 初始化当前函数的参数信息
        self.current_function_params = {param.name for param in func_node.params}
        self.parameter_usage = {
            param.name: ParameterUsageInfo(param.name) for param in func_node.params
        }

        # 分析函数体
        self.visit_statement_block(func_node.body)

        # 为每个参数设置优化后的C++类型
        for param in func_node.params:
            usage_info = self.parameter_usage.get(param.name)
            if usage_info:
                # 获取基础C++类型
                base_cpp_type = param.extension_params.get("cpp_type")
                if base_cpp_type:
                    # 根据使用模式和配置优化参数类型
                    # 传入参数节点和模块，让 usage_info 可以访问配置系统
                    optimized_type = usage_info.get_cpp_parameter_type(
                        base_cpp_type, param, self.current_module  # 参数节点  # IR 模块
                    )
                    param.extension_params["optimized_cpp_type"] = optimized_type

                    # 记录使用统计信息
                    param.extension_params["usage_stats"] = {
                        "is_read": usage_info.is_read,
                        "is_modified": usage_info.is_modified,
                        "is_mutated": usage_info.is_mutated,
                        "read_count": usage_info.read_count,
                        "modification_count": usage_info.modification_count,
                    }

    def visit_statement_block(self, stmt_block: IRStmtBlock):
        """访问语句块"""
        if hasattr(stmt_block, "statements"):
            for stmt in stmt_block.statements:
                self.visit_statement(stmt)

    def visit_statement(self, stmt: IRNode):
        """访问语句"""
        if isinstance(stmt, IRAssign):
            self.visit_assign(stmt)
        elif isinstance(stmt, IRAugAssign):
            self.visit_aug_assign(stmt)
        elif isinstance(stmt, IRExprStmt):
            self.visit_expression(stmt.expr)
        elif isinstance(stmt, IRReturn):
            self.visit_return(stmt)
        elif isinstance(stmt, (IRForEach, IRForRange, IRIf, IRWhile)):
            self.visit_control_flow(stmt)
        else:
            # 递归访问其他类型的语句
            for child in stmt.get_child_nodes():
                if isinstance(child, IRNode):
                    self.visit_statement(child)

    def visit_return(self, return_stmt):
        """访问return语句"""
        if hasattr(return_stmt, "expr") and return_stmt.expr:
            self.visit_expression(return_stmt.expr)

    def visit_assign(self, assign: IRAssign):
        """访问赋值语句"""
        # 检查赋值目标是否为参数
        target_expr = assign.get_target_expr()
        if target_expr:

            if isinstance(target_expr, IRName):
                param_name = target_expr.id
                if param_name and param_name in self.current_function_params:
                    usage_info = self.parameter_usage[param_name]
                    usage_info.is_modified = True
                    usage_info.modification_count += 1

        # 访问赋值表达式中的参数使用
        if hasattr(assign, "value"):
            self.visit_expression(assign.value)

    def visit_aug_assign(self, aug_assign: IRAugAssign):
        """访问增强赋值语句（如 +=, -=）"""
        # 增强赋值既读取又修改参数
        if hasattr(aug_assign, "target"):
            param_name = self._extract_param_name(aug_assign.target)
            if param_name and param_name in self.current_function_params:
                usage_info = self.parameter_usage[param_name]
                usage_info.is_read = True
                usage_info.is_modified = True
                usage_info.read_count += 1
                usage_info.modification_count += 1

        # 访问增强赋值表达式中的参数使用
        if hasattr(aug_assign, "value"):
            self.visit_expression(aug_assign.value)

    def visit_expression(self, expr: IRNode):
        """访问表达式"""
        if isinstance(expr, IRName):
            self.visit_name(expr)
        elif isinstance(expr, IRCall):
            self.visit_call(expr)
        elif isinstance(expr, IRAttribute):
            self.visit_attribute(expr)
        else:
            # 递归访问表达式的子节点
            for child in expr.get_child_nodes():
                if isinstance(child, IRNode):
                    self.visit_expression(child)

    def visit_name(self, name: IRName):
        """访问名称节点（变量引用）"""
        if hasattr(name, "id") and name.id in self.current_function_params:
            usage_info = self.parameter_usage[name.id]
            usage_info.is_read = True
            usage_info.read_count += 1

    def visit_call(self, call: IRCall):
        """访问函数调用"""
        # 检查是否为参数的方法调用
        if isinstance(call.func, IRAttribute):
            self.visit_method_call(call)

        # 访问函数调用的参数
        if hasattr(call, "args"):
            for arg in call.args:
                self.visit_expression(arg)

        # 访问函数对象
        if hasattr(call, "func"):
            self.visit_expression(call.func)

    def visit_method_call(self, call: IRCall):
        """访问方法调用 - 利用builtin_table信息"""
        attr = call.func
        if isinstance(attr, IRAttribute):
            if hasattr(attr, "value") and isinstance(attr.value, IRName):
                if (
                    hasattr(attr.value, "id")
                    and attr.value.id in self.current_function_params
                ):
                    param_name = attr.value.id
                    method_name = getattr(attr, "attr", "")

                    usage_info = self.parameter_usage[param_name]

                    # 方法调用总是读取对象
                    usage_info.is_read = True
                    usage_info.read_count += 1

                    # 利用builtin_table判断方法是否会修改对象
                    if self._is_mutating_method_from_config(method_name):
                        usage_info.is_mutated = True
                        usage_info.modification_count += 1

    def visit_attribute(self, attr: IRAttribute):
        """访问属性访问"""
        # 访问属性的对象
        if hasattr(attr, "value"):
            self.visit_expression(attr.value)

    def visit_control_flow(self, stmt: IRNode):
        """访问控制流语句"""
        # 访问条件表达式
        if hasattr(stmt, "test"):
            self.visit_expression(getattr(stmt, "test"))

        # 访问循环/条件体
        for attr_name in [
            "body",
            "then_body",
            "else_body",
            "iter_expr",
            "start",
            "end",
            "step",
        ]:
            if hasattr(stmt, attr_name):
                attr_value = getattr(stmt, attr_name)
                if attr_value:
                    if hasattr(attr_value, "statements"):  # 语句块
                        self.visit_statement_block(attr_value)
                    elif isinstance(attr_value, IRNode):  # 表达式
                        self.visit_expression(attr_value)

    def _extract_param_name(self, target) -> Optional[str]:
        """从赋值目标提取参数名"""
        if isinstance(target, IRName):
            return target.id
        elif isinstance(target, str):
            return target
        return None

    def _is_mutating_method_from_config(self, method_name: str) -> bool:
        """从builtin_table配置判断方法是否会修改对象

        利用BUILTIN_CONFIG中的方法信息，避免硬编码
        """
        # 遍历所有类型配置，查找方法信息
        from ..builtin.builtin_table import BUILTIN_CONFIG

        for type_name, config in BUILTIN_CONFIG.items():
            if "methods" in config:
                methods = config["methods"]
                if method_name in methods:
                    method_config = methods[method_name]
                    # 检查方法是否标记为修改性的
                    # 配置中可能使用 "mutating" 或 "is_mutating" 键
                    if isinstance(method_config, dict):
                        return method_config.get(
                            "mutating", method_config.get("is_mutating", False)
                        )

        # 如果没有找到配置，使用简单的启发式规则
        mutating_patterns = {
            "append",
            "extend",
            "insert",
            "remove",
            "pop",
            "clear",
            "sort",
            "reverse",
            "update",
            "add",
            "discard",
            "push",
            "push_back",
            "emplace",
            "emplace_back",
        }
        return method_name in mutating_patterns
